package com.xjscrm.server.service.grouppulljob.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.uzai.mobile.collect.api.enums.MicaMsgSource;
import com.uzai.mobile.collect.api.enums.MicaTalkMsgType;
import com.uzai.trace.TraceGenerate;
import com.xjscrm.common.annotation.MerId;
import com.xjscrm.common.entity.*;
import com.xjscrm.common.exception.BusinessException;
import com.xjscrm.common.result.ResponseCode;
import com.xjscrm.common.utils.DateUtil;
import com.xjscrm.common.utils.Tools;
import com.xjscrm.common.vo.grouppull.GroupPullData;
import com.xjscrm.common.vo.grouppull.GroupPullMsgData;
import com.xjscrm.server.biz.RatelimitService;
import com.xjscrm.server.common.util.DeviceTools;
import com.xjscrm.server.common.util.SleepTimeTools;
import com.xjscrm.server.dto.grouppulljobmsg.GroupPullJobMsgQuery;
import com.xjscrm.server.dto.grouppulltaskcustomer.GroupPullTaskCustomerQuery;
import com.xjscrm.server.dto.wwcustomer.WwCustomerQuery;
import com.xjscrm.server.mapper.*;
import com.xjscrm.server.req.filterrule.CustomerBasicInfoExcludeFilterReq;
import com.xjscrm.server.req.filterrule.CustomerTimeExcludeFilterReq;
import com.xjscrm.server.req.filterrule.CustomerTagsExcludeFilterReq;
import com.xjscrm.server.service.customer.WwCustomerTagsService;
import com.xjscrm.server.service.filterrule.CustomerCommonFilterService;
import com.xjscrm.server.service.grouppull.GroupPullDataService;
import com.xjscrm.server.service.grouppulljob.GroupPullMsgService;
import com.xjscrm.server.service.msg.MsgSendService;
import com.xjscrm.server.vo.device.Device;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 拉群任务异步实现类
 *
 * @author makejava
 * @since 2024-03-01 17:01:12
 */
@Slf4j
@Service
public class GroupPullMsgServiceImpl implements GroupPullMsgService, CustomerCommonFilterService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private GroupPullTaskMapper groupPullJobMapper;
    @Autowired
    private RatelimitService ratelimitService;
    @Autowired
    private GroupPullJobDeviceMapper groupPullJobDeviceMapper;
    @Autowired
    private GroupPullTaskDeviceConfigMapper groupPullJobDeviceConfigMapper;
    @Autowired
    private WwCustomerWhitelistMapper wwCustomerWhitelistMapper;
    @Autowired
    private WwCustomerTagsMapper wwCustomerTagsMapper;
    @Autowired
    private WwGroupTagsRelationMapper wwGroupTagsRelationMapper;
    @Autowired
    private WwCustomerMapper wwCustomerMapper;
    @Autowired
    private WwGroupMapper wwGroupMapper;
    @Autowired
    private WwGroupMemberMapper wwGroupMemberMapper;
    @Autowired
    private GroupPullJobMsgMapper groupPullJobMsgMapper;
    @Autowired
    private GroupPullTaskCustomerMapper groupPullTaskCustomerMapper;
    @Autowired
    private MsgSendService msgSendService;
    @Autowired
    private WwDeviceMapper wwDeviceMapper;
    @Autowired
    private GroupPullDataService groupPullDataService;
    @Autowired
    private WwCustomerBlacklistMapper wwCustomerBlacklistMapper;
    @Resource
    private WwCustomerTagsService wwCustomerTagsService;

    /**
     * 添加拉群消息
     *
     * @param groupPullJob
     * @return null
     * @author jitwxs
     * @date 2024/3/8 17:12
     */
    @Async("taskExecutorForXxJob")
    public void addGroupPullMsg(@MerId Long merId, GroupPullJob groupPullJob, GroupPullJobDevice groupPullJobDevice) {
        if (groupPullJobDevice == null) {
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "拉群机器人不存在");
        }
        //查询机器人信息
        WwDevice wwDevice = wwDeviceMapper.queryByDeviceId(groupPullJobDevice.getDeviceId(), groupPullJobDevice.getMerId());
        if (wwDevice == null) {
            return;
        }
        Device device = DeviceTools.transDevice(wwDevice);
        if (device == null) {
            return;
        }

        //封装拉群数据
        String groupPullDatas = groupPullJob.getGuider();
        List<GroupPullData> groupPullDataList = JSONObject.parseArray(groupPullDatas, GroupPullData.class);
        if (groupPullDataList == null || groupPullDataList.size() == 0) {
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, "拉群数据为空");
        }

        int now = DateUtil.getTime();

        //消息延迟时间
        int delay = 0;

        //筛选类型(0-全部客户；1-筛选客户；2-选择客户)
        Integer customerType = Tools.getInteger(groupPullJob.getCustomerType());
        if (customerType.intValue() == 0 || customerType.intValue() == 1) {//需要遍历客户表
            //查询所有的客户
            WwCustomerQuery wwCustomerQuery = new WwCustomerQuery();
            wwCustomerQuery.setMerId(groupPullJob.getMerId());
            wwCustomerQuery.setDeviceUniqueId(groupPullJobDevice.getDeviceUniqueId());
            Page<WwCustomer> page = new Page<>();
            page.setCurrent(1);//只查第一页
            page.setSize(10); //每页查询10个
            page.addOrder(OrderItem.asc("id"));//默认id升序
            Long idStart = 0L;
            List<WwCustomer> wwCustomerList = wwCustomerMapper.findByList(page, wwCustomerQuery);
            while (wwCustomerList != null && wwCustomerList.size() > 0) {
                for (WwCustomer wwCustomer : wwCustomerList) {
                    try {
                        if (wwCustomer.getId().longValue() >idStart.longValue()) {
                            idStart = wwCustomer.getId();
                        }

                        //客户验证结果，默认为通过验证
                        boolean result = true;
                        if (customerType.intValue() == 1) { //按照条件筛选客户，需要验证
                            result = verifyCustomer(groupPullJob, groupPullJobDevice, wwCustomer);
                        }
                        if (result) {//符合条件，则添加消息
                            List<GroupPullMsgData> groupPullMsgDataList = groupPullDataService.handGroupPullData(merId, groupPullDataList, wwCustomer, device);
                            if (groupPullMsgDataList != null && groupPullMsgDataList.size() > 0) {
                                //发送拉群消息
                                delay = addGroupPullMsgData(groupPullJob, groupPullJobDevice, groupPullMsgDataList, wwCustomer, delay);
                            }
                        }
                    } catch (Exception e) {
                        log.error("循环所有客户拉群消息失败", e.getMessage(), e);
                    }
                }

                wwCustomerQuery.setIdStart(idStart);
                wwCustomerList = wwCustomerMapper.findByList(page, wwCustomerQuery);
            }
        } else if (customerType.intValue() == 2) { //选择客户
            //查询选择的客户
            GroupPullTaskCustomerQuery groupPullTaskCustomerQuery = new GroupPullTaskCustomerQuery();
            groupPullTaskCustomerQuery.setMerId(groupPullJob.getMerId());
            groupPullTaskCustomerQuery.setDeviceUniqueId(groupPullJobDevice.getDeviceUniqueId());
            groupPullTaskCustomerQuery.setTaskId(groupPullJob.getTaskId());

            Page<GroupPullTaskCustomer> page = new Page<>();
            page.setCurrent(1);//只查第一页
            page.setSize(10); //每页查询10个
            page.addOrder(OrderItem.asc("id"));//默认id升序
            Long idStart = 0L;
            List<GroupPullTaskCustomer> groupPullTaskCustomerList = groupPullTaskCustomerMapper.findByList(page, groupPullTaskCustomerQuery);
            while (groupPullTaskCustomerList != null && groupPullTaskCustomerList.size() > 0) {
                for (GroupPullTaskCustomer groupPullTaskCustomer : groupPullTaskCustomerList) {
                    try {
                        if (groupPullTaskCustomer.getId().longValue() >idStart.longValue()) {
                            idStart = groupPullTaskCustomer.getId();
                        }

                        //默认黑名单不通过
                        WwCustomerBlacklist wwCustomerBlacklist = wwCustomerBlacklistMapper.selectByWxid(groupPullTaskCustomer.getMerId(), groupPullTaskCustomer.getWxid());
                        if(wwCustomerBlacklist != null){ //在黑名单中
                            log.info("黑名单会员wxid={}, merId={}", groupPullTaskCustomer.getWxid(), groupPullTaskCustomer.getMerId());
                            continue;
                        }

                        WwCustomer wwCustomer = wwCustomerMapper.queryByDeviceUniqueIdAndWxid(groupPullTaskCustomer.getDeviceUniqueId(), groupPullTaskCustomer.getWxid());
                        if (wwCustomer != null) {
                            List<GroupPullMsgData> groupPullMsgDataList = groupPullDataService.handGroupPullData(merId, groupPullDataList, wwCustomer, device);
                            if (groupPullMsgDataList != null && groupPullMsgDataList.size() > 0) {
                                //发送拉群消息
                                delay = addGroupPullMsgData(groupPullJob, groupPullJobDevice, groupPullMsgDataList, wwCustomer, delay);
                            }
                        }
                    } catch (Exception e) {
                        log.error("--循环选择客户拉群消息失败", e.getMessage(), e);
                    }
                }
                groupPullTaskCustomerQuery.setIdStart(idStart);
                groupPullTaskCustomerList = groupPullTaskCustomerMapper.findByList(page, groupPullTaskCustomerQuery);
            }
        }
    }

    /**
     * 验证会员是否符合条件
     *
     * @param wwCustomer 聊天消息
     * @return 实例对象
     */
    private boolean verifyCustomer(GroupPullJob groupPullJob, GroupPullJobDevice groupPullJobDevice, WwCustomer wwCustomer) {

        if (wwCustomer == null) {
            return false;
        }

        //客户类型(0-全部客户；1-部分客户)
        Integer customerType = Tools.getInteger(groupPullJob.getCustomerType());
        if (customerType.intValue() == 1) { //部分客户，则需要验证条件
            //获取客户已打的标签
            List<Long> wwCustomerTagedList = wwCustomerTagsService.getTagIds(wwCustomer.getMerId(), wwCustomer.getId());
            CustomerTagsExcludeFilterReq customerTagsExcludeFilterReq = new CustomerTagsExcludeFilterReq(groupPullJob.getExcludeCustomerEnterpriseTagOpt(), groupPullJob.getExcludeCustomerEnterpriseTags(), wwCustomerTagedList, groupPullJob.getOpenExclude());
            CustomerTimeExcludeFilterReq customerTimeExcludeFilterReq = new CustomerTimeExcludeFilterReq(groupPullJob.getExcludeNewCustomer(), wwCustomer.getCreateTime(), groupPullJob.getExcludeCustomerCreateDayStart(), groupPullJob.getExcludeCustomerCreateDayEnd(), groupPullJob.getOpenExclude());
            CustomerBasicInfoExcludeFilterReq customerBasicInfoExcludeFilterReq = new CustomerBasicInfoExcludeFilterReq(wwCustomer, groupPullJob.getExcludeCustomerRemarkOpt(), groupPullJob.getExcludeCustomerGenders(), groupPullJob.getOpenExclude());
            if (this.excludeFilter(customerTagsExcludeFilterReq, customerTimeExcludeFilterReq, customerBasicInfoExcludeFilterReq)) {
                return false;
            }
            //客户企业标签选项(0-含任意标签；1-含所有标签；2-未打任何标签)
            Integer customerEnterpriseTagOpt = groupPullJob.getCustomerEnterpriseTagOpt();
            if (customerEnterpriseTagOpt != null) {
                //2-未打任何标签
                if (customerEnterpriseTagOpt.intValue() == 2) {
                    if (wwCustomerTagedList.size() > 0) {
                        return false;
                    }
                } else {
                    //标签列表
                    List<Long> customerEnterpriseTagList = JSONObject.parseArray(groupPullJob.getCustomerEnterpriseTags(), Long.class);
                    if (customerEnterpriseTagList == null || customerEnterpriseTagList.size() == 0) { //没有找到，则不回复
                        return false;
                    }
                    if (customerEnterpriseTagOpt.intValue() == 0) { //满足任意一个
                        boolean tagFlag = false;
                        for (Long customerEnterpriseTag : customerEnterpriseTagList) {
                            if (wwCustomerTagedList.contains(customerEnterpriseTag)) {//找到一个符合的，就返回通过
                                tagFlag = true;
                                break;
                            }
                        }
                        if (!tagFlag) {
                            return false;
                        }
                    } else if (customerEnterpriseTagOpt.intValue() == 1) {//满足所有触发
                        if (!wwCustomerTagedList.containsAll(customerEnterpriseTagList)) {
                            return false;
                        }
                    }
                }
            }

            //加好友时间
            String customerCreateDayStart = groupPullJob.getCustomerCreateDayStart();
            String customerCreateDayEnd = groupPullJob.getCustomerCreateDayEnd();
            if (StringUtils.isNotBlank(customerCreateDayStart)
                    && StringUtils.isNotBlank(customerCreateDayEnd)
            ) {
                Integer customerCreateTime = wwCustomer.getCreateTime();
                if (customerCreateTime == null) {//如果没有添加好友时间，则不通过
                    return false;
                }
                //判断旧发送时间是否在允许区间内
                Instant instant_groupCreateTime = Instant.ofEpochMilli(customerCreateTime * 1000L);
                LocalDateTime localDateTime = LocalDateTime.ofInstant(instant_groupCreateTime, ZoneId.systemDefault());
                boolean withinTimeInterval_customerCreateTime = Tools.isWithinDateInterval(localDateTime, LocalDate.parse(customerCreateDayStart), LocalDate.parse(customerCreateDayEnd));
                if (!withinTimeInterval_customerCreateTime) {
                    return false;
                }
            }

            //客户备注选项(0-无备注；1-有备注)
            Integer customerRemarkOpt = groupPullJob.getCustomerRemarkOpt();
            if (customerRemarkOpt != null) {
                if (customerRemarkOpt.intValue() == 0) {//无备注
                    if (StringUtils.isNotBlank(wwCustomer.getRemark())) {
                        return false;
                    }
                } else if (customerRemarkOpt.intValue() == 1) { //有备注
                    if (StringUtils.isBlank(wwCustomer.getRemark())) {
                        return false;
                    }
                }
            }

            //性别(0-未知；1-男；2-女)
            Integer customerGenders = groupPullJob.getCustomerGenders();
            if (customerGenders != null) {
                //验证客户性别是否跟配置的符合
                if (customerGenders.intValue() != Tools.getInteger(wwCustomer.getGender()).intValue()) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 封装拉群数据
     *
     * @param groupPullJob
     * @param groupPullJobDevice
     * @param wwCustomer
     * @return int
     * @author jitwxs
     * @date 2024/4/1 18:52
     */
    public int addGroupPullMsgData(GroupPullJob groupPullJob, GroupPullJobDevice groupPullJobDevice, List<GroupPullMsgData> groupPullMsgDataList, WwCustomer wwCustomer, int delay) {

        String sendWxid = null;
        String sendNickname = null;

        if (wwCustomer != null) {
            sendWxid = wwCustomer.getWxid();
            //替换[称呼/昵称]变量，优先称呼，在昵称
            sendNickname = wwCustomer.getNickname();
            if (StringUtils.isBlank(sendNickname)) {
                sendNickname = wwCustomer.getName();
            }
        }

        if (StringUtils.isBlank(sendWxid)) {
            return delay;
        }

        if (groupPullMsgDataList == null || groupPullMsgDataList.size() == 0) {
            return delay;
        }

        //每个会员的间隔时间
        Integer rateMin = Tools.getInteger(groupPullJobDevice.getRateMin());
        Integer rateMax = Tools.getInteger(groupPullJobDevice.getRateMax());
        int randomRate = SleepTimeTools.randomRate(rateMin, rateMax);
        delay = delay + randomRate; //累加每个会员间隔时间

        for (GroupPullMsgData groupPullMsgData : groupPullMsgDataList) {
            delay = delay + Tools.getInteger(groupPullMsgData.getGap()) * Tools.getInteger(groupPullMsgData.getUnit());
            GroupPullJobMsg groupPullJobMsg = new GroupPullJobMsg();
            groupPullJobMsg.setId(IdWorker.getId());
            groupPullJobMsg.setMerId(groupPullJobDevice.getMerId());
            groupPullJobMsg.setJobId(groupPullJobDevice.getJobId());
            groupPullJobMsg.setStatus(1); //未发送
            groupPullJobMsg.setDeviceUniqueId(groupPullJobDevice.getDeviceUniqueId());
            groupPullJobMsg.setSendWxid(sendWxid);
            groupPullJobMsg.setMsgType(groupPullMsgData.getMsgType());
            groupPullJobMsg.setGroupWxid(groupPullMsgData.getGroupId());
            //替换[称呼/昵称]变量，优先称呼，在昵称
            if (groupPullMsgData.getMsgType().intValue() == MicaTalkMsgType.TEXT.getCode().intValue()) {//文本消息
                String content = Tools.getStr(groupPullMsgData.getContent());
                content = content.replace("[称呼/昵称]", Tools.getStr(sendNickname));
                groupPullMsgData.setContent(content);
            }
            groupPullJobMsg.setGroupPullMsgData(JSONObject.toJSONString(groupPullMsgData));
            groupPullJobMsg.setDelay(delay);
            groupPullJobMsg.setCreateTime(groupPullJobDevice.getCreateTime());
            groupPullJobMsg.setUpdateTime(groupPullJobDevice.getCreateTime());
            groupPullJobMsgMapper.insertSelective(groupPullJobMsg);
        }

        return delay;
    }

    /**
     * 将拉群数据封装到MQ
     *
     * @param merId
     * @return null
     * @author jitwxs
     * @date 2024/3/8 17:12
     */
    @Async("taskExecutorForXxJob")
    @TraceGenerate //注入消息id标签
    public void groupPullJobMsgToMqSync(@MerId Long merId, GroupPullJob groupPullJob, GroupPullJobDevice groupPullJobDevice) {
        //限流key
        String taskLimitKey = "-groupPullJobMsgToMqSync-taskLimitKey-groupPullJobDeviceId=" + groupPullJobDevice.getId();
        Object object = redisTemplate.opsForValue().get(taskLimitKey);
        if (object != null) {
            return;
        }

        //封装MQ
        WwDevice wwDevice = wwDeviceMapper.queryById(groupPullJobDevice.getDeviceUniqueId());
        if (wwDevice == null) {
            return;
        }
        Device device = DeviceTools.transDevice(wwDevice);

        //保存限流key
        redisTemplate.opsForValue().set(taskLimitKey, groupPullJobDevice.getId(), 100, TimeUnit.SECONDS);

        log.info("-----将拉群消息封装到MQ----merId=" + merId);

        try {
            //查询该机器人任务的延迟快照时间
            Integer delaySnapshot = Tools.getInteger(groupPullJobDevice.getDelaySnapshot());

            //查询当前所有开启的自动发圈的配置方案
            int now = DateUtil.getTime();
            int startSendTime = Tools.getInteger(groupPullJob.getStartSendTime()).intValue();
            //计算当前时间和开始发送时间之前的差值
            int dif_now_startSendTime = now - startSendTime;
            GroupPullJobMsgQuery groupPullJobMsgQuery = new GroupPullJobMsgQuery();
            groupPullJobMsgQuery.setMerId(merId);
            groupPullJobMsgQuery.setDeviceUniqueId(groupPullJobDevice.getDeviceUniqueId());
            groupPullJobMsgQuery.setJobId(groupPullJobDevice.getJobId());
            groupPullJobMsgQuery.setDelayEnd(now - startSendTime + 30); //30秒内的所有消息插入到mq当中
            groupPullJobMsgQuery.setStatus(1); //状态（1-未发送；2-已发送；3-发送失败)

            //查询所有的自动发圈配置记录
            Page<GroupPullJobMsg> page = new Page<>();
            page.setCurrent(1);//只查第一页
            page.setSize(10); //每页查询10个
            page.addOrder(OrderItem.asc("id"));//默认id升序
            Long idStart = 0L;
            List<GroupPullJobMsg> groupPullJobMsgList = groupPullJobMsgMapper.findByList(page, groupPullJobMsgQuery);
            if (groupPullJobMsgList != null && groupPullJobMsgList.size() > 0) {
                for (GroupPullJobMsg groupPullJobMsg : groupPullJobMsgList) {
                    if (groupPullJobMsg.getId().longValue() >idStart.longValue()) {
                        idStart = groupPullJobMsg.getId();
                    }

                    //限流判断
                    String rateLimitKey = "groupPullJobMsgToMqSync-msgId=" + groupPullJobMsg.getId();
                    Object rateLimitKeyObject = redisTemplate.opsForValue().get(rateLimitKey);
                    if (rateLimitKeyObject == null) {
                        redisTemplate.opsForValue().set(rateLimitKey, rateLimitKey, 300, TimeUnit.SECONDS);
                    }else{
                        continue;
                    }

                    try {

                        if(Tools.getInteger(groupPullJobMsg.getDelay()).intValue() > delaySnapshot.intValue()){
                            delaySnapshot = Tools.getInteger(groupPullJobMsg.getDelay());
                        }

                        //默认黑名单不通过
                        WwCustomerBlacklist wwCustomerBlacklist = wwCustomerBlacklistMapper.selectByWxid(groupPullJobMsg.getMerId(), groupPullJobMsg.getSendWxid());
                        if(wwCustomerBlacklist != null){ //在黑名单中
                            log.info("黑名单会员wxid={}, merId={}", groupPullJobMsg.getSendWxid(), groupPullJobMsg.getMerId());
                            //处理群发任务
                            groupPullJobMsg.setStatus(3); //状态（1-未发送；2-已发送；3-发送失败)
                            groupPullJobMsg.setUpdateTime(DateUtil.getTime());
                            groupPullJobMsgMapper.updateStatusById(groupPullJobMsg);
                        }else{
                            //处理拉群任务
                            groupPullJobMsg.setStatus(2); //状态（1-未发送；2-已发送；3-发送失败)
                            groupPullJobMsg.setUpdateTime(DateUtil.getTime());
                            groupPullJobMsgMapper.updateStatusById(groupPullJobMsg);
                            GroupPullMsgData groupPullMsgData = JSONObject.parseObject(groupPullJobMsg.getGroupPullMsgData(), GroupPullMsgData.class);
                            if (groupPullMsgData != null) {
                                groupPullMsgData.setGap(groupPullJobMsg.getDelay());
                                groupPullMsgData.setUnit(1); //秒
                            }
                            msgSendService.groupPullMsgSend(merId, device, groupPullJobMsg.getSendWxid(), null, groupPullMsgData, 3, groupPullJobMsg.getJobId(), false, null, dif_now_startSendTime, MicaMsgSource.GROUP_PULL_JOB.getCode(), false);
                        }
                    } catch (Exception e) {
                        log.error("--封装拉群消息失败--error={}", e.getMessage(), e);
                    } finally {
                        //保存成功之后，手动删除限流redisKey
                        redisTemplate.delete(rateLimitKey);
                    }
                }

            //修改子任务的延迟快照时间
            groupPullJobDevice.setDelaySnapshot(delaySnapshot);
            groupPullJobDeviceMapper.updateDelaySnapshotById(groupPullJobDevice);

//                groupPullJobMsgQuery.setIdStart(idStart);
//                groupPullJobMsgList = groupPullJobMsgMapper.findByList(page, groupPullJobMsgQuery);
            }
        } catch (Exception e) {
            log.info(e.getMessage(),e);
        } finally {
            //删除限流key
            redisTemplate.delete(taskLimitKey);
        }

    }


}
